﻿using Furion.CMS.Core;
using Furion.CMS.Core.EventSource;
using Furion.DatabaseAccessor;
using Furion.DependencyInjection;
using Furion.DistributedIDGenerator;
using Furion.EventBus;
using Furion.TaskScheduler;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;

namespace Furion.CMS.Domain
{
    [OperateRecord("角色管理")]
    public class RoleInfo : Entity, IEntityTypeBuilder<RoleInfo>,
        IEntitySeedData<RoleInfo>,
        IEntityChangedListener<RoleInfo>
    {
        public RoleInfo()
        {
            Code = IDGen.NextID().ToString(); //生成一个连续的Guid
            CreatedTime = DateTimeOffset.UtcNow;
            Users = new HashSet<UserInfo>();
            Permissions = new HashSet<PermissionInfo>();
        }

        /// <summary>
        /// 唯一代码
        /// </summary>
        [MaxLength(36), Required]
        public string Code { get; set; }
        /// <summary>
        /// 名称
        /// </summary>
        [MaxLength(100), Required]
        [OperateRecord("角色管理", true)]
        public string Name { get; set; }
        /// <summary>
        /// 策略名称
        /// </summary>
        [MaxLength(100)]
        public string PolicyName { get; set; }
        /// <summary>
        /// 描述
        /// </summary>
        [MaxLength(400)]
        public string Description { get; set; }
        /// <summary>
        /// 是种子数据
        /// </summary>
        public bool HasSeed { get; set; }
        /// <summary>
        /// 是否是默认角色
        /// </summary>
        [OperateRecord("是否是默认角色")]
        public bool IsDefault { get; set; }
        /// <summary>
        /// 角色授权人员集合
        /// </summary>
        public virtual ICollection<UserInfo> Users { get; set; }
        /// <summary>
        /// 角色权限集合
        /// </summary>
        public virtual ICollection<PermissionInfo> Permissions { get; set; }
        /// <summary>
        /// 所属机构
        /// </summary>
        public virtual ICollection<OrganizationInfo> Organizations { get; set; }

        public void Configure(EntityTypeBuilder<RoleInfo> entityBuilder, DbContext dbContext, Type dbContextLocator)
        {
            entityBuilder.UseDefaultTableNameDefine();

            entityBuilder.HasMany(p => p.Permissions)
                .WithMany(p => p.Roles)
                .UsingEntity<RolePermission>(
                r => r.HasOne(x => x.Permission).WithMany().HasForeignKey(x => x.PermissionCode),
                l => l.HasOne(x => x.Role).WithMany().HasForeignKey(x => x.RoleId)
                );
        }

        public IEnumerable<RoleInfo> HasData(DbContext dbContext, Type dbContextLocator)
        {
            return new List<RoleInfo>()
            {
                new RoleInfo{ Id=1, Name="超级管理员", PolicyName=LocalPolicyConsts.SuperAdmin, Description="超级管理员，拥有全部权限的系统角色不可删除",HasSeed = true }
            };
        }

        public void OnChanging(RoleInfo entity, DbContext dbContext, Type dbContextLocator, EntityState state)
        {
            if (state == EntityState.Deleted)
            {// 删除前预先加载指定集合数据用于缓存更新与服务通知推送
                dbContext.Entry(entity).Collection(c => c.Users).Load();
                dbContext.Entry(entity).Collection(c => c.Permissions).Load();
                dbContext.Entry(entity).Collection(c => c.Organizations).Query()
                    .Include(i => i.Users).Load();
            }
        }

        public void OnChanged(RoleInfo newEntity, RoleInfo oldEntity, DbContext dbContext, Type dbContextLocator, EntityState state)
        {
            if (state == EntityState.Detached)
            {
                SpareTime.DoIt(() =>
                {
                    var changeEvents = new List<OnPermissionDataItemChange>();
                    /*
                     * 清除模块缓存
                     * 清除资源关联缓存
                     */
                    var changeModuleKey = string.Format(CacheKeyConsts.PermissionModule, newEntity.Code);
                    changeEvents.Add(new OnPermissionDataItemChange(CacheOperationType.Clear, changeModuleKey));
                    // 资源
                    var dependentResList = newEntity.Permissions.Where(t => !string.IsNullOrWhiteSpace(t.DependentResources))
                    .SelectMany(s => s.DependentResources.Split(new String[] { "," }, StringSplitOptions.RemoveEmptyEntries));
                    var allUsers = newEntity.Users.UnionBy(newEntity.Organizations.SelectMany(s => s.Users), u => u.Id);
                    var roleUsers = newEntity.Users.Select(s => string.Format(CacheKeyConsts.PermissionResourceValue, newEntity.Code, s.Id));
                    var roleOrgs = newEntity.Organizations.SelectMany(s => s.Users, (org, user) => string.Format(CacheKeyConsts.PermissionResourceValue, org.Id, user.Id));
                    var resourcePayload = roleUsers.Union(roleOrgs);
                    changeEvents.AddRange(dependentResList.Select(s => new OnPermissionDataItemChange(CacheOperationType.Remove, string.Format(CacheKeyConsts.PermissionResource, s, ""), resourcePayload)));

                    var eventCenter = App.GetService<IEventPublisher>();
                    // 触发缓存更新事件
                    eventCenter?.PublishAsync(new ChannelEventSource(EventIdConsts.PermissionDataItemManyChange, changeEvents));
                    // 前端推送事件
                    var triggerEvetns = allUsers.Select(s => new OnTriggerOuterEvent(OuterEventCategory.UserRefresh, s.Id.ToString()));
                    eventCenter?.PublishDelayAsync(new ChannelEventSource(EventIdConsts.TriggerManyOuterEvent, triggerEvetns), 1000);
                });
            }
        }
    }
}
